{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zg02FZzDyEqd"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "2mapZ9afGJ69"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sMYQvJuBi7MS"
      },
      "source": [
        "# Keras 전처리 레이어를 사용한 구조적 데이터 분류"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8FaL4wnr22oy"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/structured_data/preprocessing_layers\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/tutorials/structured_data/preprocessing_layers.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/tutorials/structured_data/preprocessing_layers.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/tutorials/structured_data/preprocessing_layers.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Nna1tOKxyEqe"
      },
      "source": [
        "이 튜토리얼에서는 구조적 데이터(예: CSV의 표 형식 데이터)를 분류하는 방법을 보여줍니다. [Keras](https://www.tensorflow.org/guide/keras)를 사용하여 모델을 정의하고, [전처리 레이어](https://keras.io/guides/preprocessing_layers/)를 CSV의 열에서 모델 훈련에 사용되는 특성으로 매핑하는 브리지로 사용합니다. 이 튜토리얼에는 다음을 위한 전체 코드가 포함되어 있습니다.\n",
        "\n",
        "- [Pandas](https://pandas.pydata.org/)를 사용하여 CSV 파일을 로드합니다.\n",
        "- [tf.data](https://www.tensorflow.org/guide/datasets)를 사용하여 행을 일괄 처리하고 셔플하는 입력 파이프라인을 빌드합니다.\n",
        "- Keras 전처리 레이어를 사용하여 CSV의 열에서 모델을 훈련하는 데 사용되는 특성으로 매핑합니다.\n",
        "- Keras를 사용하여 모델을 빌드, 훈련 및 평가합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "h5xkXCicjFQD"
      },
      "source": [
        "참고: 이 튜토리얼은 [특성 열의 구조적 데이터 분류하기](https://www.tensorflow.org/tutorials/structured_data/feature_columns)와 유사합니다. 이 버전은 `tf.feature_column` 대신 새로운 실험용 Keras [전처리 레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing)를 사용합니다. Keras Preprocessing Layer는 더 직관적이며 배포를 단순화하기 위해 모델 내에 쉽게 포함될 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZHxU1FMNpomc"
      },
      "source": [
        "## 데이터세트\n",
        "\n",
        "PetFinder [데이터세트](https://www.kaggle.com/c/petfinder-adoption-prediction)의 단순화된 버전을 사용합니다. CSV에는 수천 개의 행이 있습니다. 각 행은 애완 동물을 설명하고 각 열은 속성을 설명합니다. 이 정보를 사용하여 애완 동물의 입양 여부를 예측합니다.\n",
        "\n",
        "다음은 이 데이터세트에 대한 설명입니다. 숫자 열과 범주 열이 모두 있습니다. 이 튜토리얼에서 사용하지 않는 자유 텍스트 열이 있습니다.\n",
        "\n",
        "열 | 설명 | 특성 유형 | 데이터 형식\n",
        "--- | --- | --- | ---\n",
        "유형 | 동물의 종류(개, 고양이) | 범주형 | 문자열\n",
        "나이 | 애완 동물의 나이 | 수치 | 정수\n",
        "품종 1 | 애완 동물의 기본 품종 | 범주형 | 문자열\n",
        "색상 1 | 애완 동물의 색상 1 | 범주형 | 문자열\n",
        "색상 2 | 애완 동물의 색상 2 | 범주형 | 문자열\n",
        "MaturitySize | 성장한 크기 | 범주형 | 문자열\n",
        "FurLength | 모피 길이 | 범주형 | 문자열\n",
        "예방 접종 | 애완 동물이 예방 접종을 받았습니다 | 범주형 | 문자열\n",
        "불임 시술 | 애완 동물이 불임 시술을 받았습니다 | 범주형 | 문자열\n",
        "건강 | 건강 상태 | 범주형 | 문자열\n",
        "회비 | 입양비 | 수치 | 정수\n",
        "설명 | 이 애완 동물에 대한 프로필 작성 | 텍스트 | 문자열\n",
        "PhotoAmt | 이 애완 동물의 업로드된 총 사진 | 수치 | 정수\n",
        "AdoptionSpeed | 입양 속도 | 분류 | 정수"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vjFbdBldyEqf"
      },
      "source": [
        "## TensorFlow 및 기타 라이브러리 가져오기\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "S_BdyQlPjfDW"
      },
      "outputs": [],
      "source": [
        "!pip install -q sklearn"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LklnLlt6yEqf"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import pandas as pd\n",
        "import tensorflow as tf\n",
        "\n",
        "from sklearn.model_selection import train_test_split\n",
        "from tensorflow.keras import layers\n",
        "from tensorflow.keras.layers.experimental import preprocessing"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UXvBvobayEqi"
      },
      "source": [
        "## Pandas를 사용하여 데이터 프레임 만들기\n",
        "\n",
        "[Pandas](https://pandas.pydata.org/)는 구조적 데이터를 로드하고 처리하는 데 유용한 여러 유틸리티가 포함된 Python 라이브러리입니다. Pandas를 사용하여 URL에서 데이터세트를 다운로드하고 데이터 프레임에 로드합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qJ4Ajn-YyEqj"
      },
      "outputs": [],
      "source": [
        "import pathlib\n",
        "\n",
        "dataset_url = 'http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip'\n",
        "csv_file = 'datasets/petfinder-mini/petfinder-mini.csv'\n",
        "\n",
        "tf.keras.utils.get_file('petfinder_mini.zip', dataset_url,\n",
        "                        extract=True, cache_dir='.')\n",
        "dataframe = pd.read_csv(csv_file)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3uiq4hoIGyXI"
      },
      "outputs": [],
      "source": [
        "dataframe.head()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C3zDbrozyEqq"
      },
      "source": [
        "## 목표 변수 만들기\n",
        "\n",
        "Kaggle 대회에서의 작업은 애완 동물이 입양되는 속도를 예측하는 것입니다(예: 첫 주, 첫 달, 첫 3개월 등). 튜토리얼을 위해 단순화해 봅시다. 여기에서는 입양 속도를 이진 분류 문제로 변환하고 단순히 애완 동물이 입양되었는지 여부를 예측합니다.\n",
        "\n",
        "레이블 열을 수정한 후, 0은 애완 동물이 입양되지 않았음을 나타내고 1은 입양되었음을 나타냅니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wmMDc46-yEqq"
      },
      "outputs": [],
      "source": [
        "# In the original dataset \"4\" indicates the pet was not adopted.\n",
        "dataframe['target'] = np.where(dataframe['AdoptionSpeed']==4, 0, 1)\n",
        "\n",
        "# Drop un-used columns.\n",
        "dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sp0NCbswyEqs"
      },
      "source": [
        "## 데이터 프레임을 훈련, 검증 및 테스트로 분할하기\n",
        "\n",
        "다운로드한 데이터세트는 단일 CSV 파일입니다. 이를 훈련, 검증 및 테스트 세트로 분할합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qT6HdyEwyEqt"
      },
      "outputs": [],
      "source": [
        "train, test = train_test_split(dataframe, test_size=0.2)\n",
        "train, val = train_test_split(train, test_size=0.2)\n",
        "print(len(train), 'train examples')\n",
        "print(len(val), 'validation examples')\n",
        "print(len(test), 'test examples')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C_7uVu-xyEqv"
      },
      "source": [
        "## tf.data를 사용하여 입력 파이프라인 만들기\n",
        "\n",
        "다음으로 데이터를 셔플하고 일괄 처리하기 위해 [tf.data](https://www.tensorflow.org/guide/datasets)로 데이터 프레임을 래핑합니다. 매우 큰 CSV 파일(메모리에 적합하지 않을 정도로 큰 파일)을 사용하는 경우, tf.data를 사용하여 디스크에서 직접 읽을 수 있습니다. 이 튜토리얼에서는 다루지 않습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7r4j-1lRyEqw"
      },
      "outputs": [],
      "source": [
        "# A utility method to create a tf.data dataset from a Pandas Dataframe\n",
        "def df_to_dataset(dataframe, shuffle=True, batch_size=32):\n",
        "  dataframe = dataframe.copy()\n",
        "  labels = dataframe.pop('target')\n",
        "  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))\n",
        "  if shuffle:\n",
        "    ds = ds.shuffle(buffer_size=len(dataframe))\n",
        "  ds = ds.batch(batch_size)\n",
        "  ds = ds.prefetch(batch_size)\n",
        "  return ds"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PYxIXH579uS9"
      },
      "source": [
        "이제 입력 파이프라인을 생성했으므로 반환되는 데이터의 형식을 확인하기 위해 호출해 보겠습니다. 출력을 읽기 쉽게 유지하기 위해 작은 배치 크기를 사용했습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tYiNH-QI96Jo"
      },
      "outputs": [],
      "source": [
        "batch_size = 5\n",
        "train_ds = df_to_dataset(train, batch_size=batch_size)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nFYir6S8HgIJ"
      },
      "outputs": [],
      "source": [
        "[(train_features, label_batch)] = train_ds.take(1)\n",
        "print('Every feature:', list(train_features.keys()))\n",
        "print('A batch of ages:', train_features['Age'])\n",
        "print('A batch of targets:', label_batch )"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "geqHWW54Hmte"
      },
      "source": [
        "데이터세트가 데이터 프레임의 행에서 열 값에 매핑되는 열 이름의 사전(데이터 프레임에서)을 반환하는 것을 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-v50jBIuj4gb"
      },
      "source": [
        "## 전처리 레이어의 사용을 시연합니다.\n",
        "\n",
        "Keras 전처리 레이어 API를 사용하면 Keras 네이티브 입력 처리 파이프라인을 빌드할 수 있습니다. 3개의 전처리 레이어를 사용하여 특성 전처리 코드를 보여줍니다.\n",
        "\n",
        "- [`Normalization`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Normalization) - 데이터의 특성별 정규화입니다.\n",
        "- [`CategoryEncoding`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/CategoryEncoding) 카테고리 인코딩 레이어입니다.\n",
        "- [`StringLookup`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/StringLookup) - 어휘의 문자열을 정수 인덱스로 매핑합니다.\n",
        "- [`IntegerLookup`](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/IntegerLookup) - 어휘의 정수를 정수 인덱스로 매핑합니다.\n",
        "\n",
        "[여기](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing)에서 사용 가능한 전처리 레이어의 목록을 찾을 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "twXBSxnT66o8"
      },
      "source": [
        "### 숫자 열\n",
        "\n",
        "각 숫자 특성에 대해 Normalization() 레이어를 사용하여 각 특성의 평균이 0이고 표준 편차가 1인지 확인합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OosUh4kTsK_q"
      },
      "source": [
        "`get_normalization_layer` 함수는 특성별 정규화를 숫자 특성에 적용하는 레이어를 반환합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "D6OuEKMMyEq1"
      },
      "outputs": [],
      "source": [
        "def get_normalization_layer(name, dataset):\n",
        "  # Create a Normalization layer for our feature.\n",
        "  normalizer = preprocessing.Normalization()\n",
        "\n",
        "  # Prepare a Dataset that only yields our feature.\n",
        "  feature_ds = dataset.map(lambda x, y: x[name])\n",
        "\n",
        "  # Learn the statistics of the data.\n",
        "  normalizer.adapt(feature_ds)\n",
        "\n",
        "  return normalizer"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MpKgUDyk69bM"
      },
      "outputs": [],
      "source": [
        "photo_count_col = train_features['PhotoAmt']\n",
        "layer = get_normalization_layer('PhotoAmt', train_ds)\n",
        "layer(photo_count_col)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "foWY00YBUx9N"
      },
      "source": [
        "참고: 숫자 특성(수백 개 이상)이 많은 경우, 먼저 숫자 특성을 연결하고 단일 [normalization](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Normalization) 레이어를 사용하는 것이 더 효율적입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yVD--2WZ7vmh"
      },
      "source": [
        "### 범주 열\n",
        "\n",
        "이 데이터세트에서 Type은 문자열(예: 'Dog'또는 'Cat')으로 표시됩니다. 모델에 직접 문자열을 공급할 수 없습니다. 전처리 레이어는 문자열을 원-핫 벡터로 처리합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LWlkOPwMsxdv"
      },
      "source": [
        "`get_category_encoding_layer` 함수는 어휘의 값을 정수 인덱스로 매핑하고 특성을 원-핫 인코딩하는 레이어를 반환합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GmgaeRjlDoUO"
      },
      "outputs": [],
      "source": [
        "def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):\n",
        "  # Create a StringLookup layer which will turn strings into integer indices\n",
        "  if dtype == 'string':\n",
        "    index = preprocessing.StringLookup(max_tokens=max_tokens)\n",
        "  else:\n",
        "    index = preprocessing.IntegerLookup(max_values=max_tokens)\n",
        "\n",
        "  # Prepare a Dataset that only yields our feature\n",
        "  feature_ds = dataset.map(lambda x, y: x[name])\n",
        "\n",
        "  # Learn the set of possible values and assign them a fixed integer index.\n",
        "  index.adapt(feature_ds)\n",
        "\n",
        "  # Create a Discretization for our integer indices.\n",
        "  encoder = preprocessing.CategoryEncoding(max_tokens=index.vocab_size())\n",
        "\n",
        "  # Prepare a Dataset that only yields our feature.\n",
        "  feature_ds = feature_ds.map(index)\n",
        "\n",
        "  # Learn the space of possible indices.\n",
        "  encoder.adapt(feature_ds)\n",
        "\n",
        "  # Apply one-hot encoding to our indices. The lambda function captures the\n",
        "  # layer so we can use them, or include them in the functional model later.\n",
        "  return lambda feature: encoder(index(feature))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "X2t2ff9K8PcT"
      },
      "outputs": [],
      "source": [
        "type_col = train_features['Type']\n",
        "layer = get_category_encoding_layer('Type', train_ds, 'string')\n",
        "layer(type_col)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j6eDongw8knz"
      },
      "source": [
        "종종 모델에 숫자를 직접 입력하지 않고 대신 해당 입력의 원-핫 인코딩을 사용합니다. 애완 동물의 나이를 나타내는 원시 데이터를 고려합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7FjBioQ38oNE"
      },
      "outputs": [],
      "source": [
        "type_col = train_features['Age']\n",
        "category_encoding_layer = get_category_encoding_layer('Age', train_ds,\n",
        "                                                      'int64', 5)\n",
        "category_encoding_layer(type_col)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SiE0glOPkMyh"
      },
      "source": [
        "## 사용할 열 선택하기\n",
        "\n",
        "여러 유형의 전처리 레이어를 사용하는 방법을 살펴보았습니다. 이제 레이어를 모델을 훈련하는 데 사용합니다. [Keras 함수형 API](https://www.tensorflow.org/guide/keras/functional)를 사용하여 모델을 빌드합니다. Keras 함수형 API는 [tf.keras.Sequential](https://www.tensorflow.org/api_docs/python/tf/keras/Sequential) API보다 더 유연한 모델을 생성하는 방법입니다.\n",
        "\n",
        "이 튜토리얼의 목표는 전처리 레이어를 처리하는 데 필요한 전체 코드(예: 메커니즘)를 보여주는 것입니다. 모델을 훈련하기 위해 몇 개의 열이 임의로 선택되었습니다.\n",
        "\n",
        "요점: 목표가 정확한 모델을 빌드하는 것이라면 자신의 더 큰 데이터세트를 시도하고 포함할 가장 의미 있는 특성과 표현 방법에 대해 신중하게 고려하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Uj1GoHSZ9R3H"
      },
      "source": [
        "이전에는 입력 파이프라인을 보여주기 위해 작은 배치 크기를 사용했습니다. 이제 더 큰 배치 크기로 새 입력 파이프라인을 생성해 보겠습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Rcv2kQTTo23h"
      },
      "outputs": [],
      "source": [
        "batch_size = 256\n",
        "train_ds = df_to_dataset(train, batch_size=batch_size)\n",
        "val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)\n",
        "test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Q3RBa51VkaAn"
      },
      "outputs": [],
      "source": [
        "all_inputs = []\n",
        "encoded_features = []\n",
        "\n",
        "# Numeric features.\n",
        "for header in ['PhotoAmt', 'Fee']:\n",
        "  numeric_col = tf.keras.Input(shape=(1,), name=header)\n",
        "  normalization_layer = get_normalization_layer(header, train_ds)\n",
        "  encoded_numeric_col = normalization_layer(numeric_col)\n",
        "  all_inputs.append(numeric_col)\n",
        "  encoded_features.append(encoded_numeric_col)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1FOMGfZflhoA"
      },
      "outputs": [],
      "source": [
        "# Categorical features encoded as integers.\n",
        "age_col = tf.keras.Input(shape=(1,), name='Age', dtype='int64')\n",
        "encoding_layer = get_category_encoding_layer('Age', train_ds, dtype='int64',\n",
        "                                             max_tokens=5)\n",
        "encoded_age_col = encoding_layer(age_col)\n",
        "all_inputs.append(age_col)\n",
        "encoded_features.append(encoded_age_col)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "K8C8xyiXm-Ie"
      },
      "outputs": [],
      "source": [
        "# Categorical features encoded as string.\n",
        "categorical_cols = ['Type', 'Color1', 'Color2', 'Gender', 'MaturitySize',\n",
        "                    'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Breed1']\n",
        "for header in categorical_cols:\n",
        "  categorical_col = tf.keras.Input(shape=(1,), name=header, dtype='string')\n",
        "  encoding_layer = get_category_encoding_layer(header, train_ds, dtype='string',\n",
        "                                               max_tokens=5)\n",
        "  encoded_categorical_col = encoding_layer(categorical_col)\n",
        "  all_inputs.append(categorical_col)\n",
        "  encoded_features.append(encoded_categorical_col)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YHSnhz2fyEq3"
      },
      "source": [
        "## 모델 생성, 컴파일 및 훈련하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IDGyN_wpo0XS"
      },
      "source": [
        "이제 엔드 투 엔드 모델을 만들 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6Yrj-_pr6jyL"
      },
      "outputs": [],
      "source": [
        "all_features = tf.keras.layers.concatenate(encoded_features)\n",
        "x = tf.keras.layers.Dense(32, activation=\"relu\")(all_features)\n",
        "x = tf.keras.layers.Dropout(0.5)(x)\n",
        "output = tf.keras.layers.Dense(1)(x)\n",
        "model = tf.keras.Model(all_inputs, output)\n",
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n",
        "              metrics=[\"accuracy\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f6mNMfG6yEq5"
      },
      "source": [
        "연결 그래프를 시각화해 보겠습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Y7Bkx4c7yEq5"
      },
      "outputs": [],
      "source": [
        "# rankdir='LR' is used to make the graph horizontal.\n",
        "tf.keras.utils.plot_model(model, show_shapes=True, rankdir=\"LR\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CED6OStLyEq7"
      },
      "source": [
        "### 모델 훈련하기\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OQfE3PC6yEq8"
      },
      "outputs": [],
      "source": [
        "model.fit(train_ds, epochs=10, validation_data=val_ds)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "T8N2uAdU2Cni"
      },
      "outputs": [],
      "source": [
        "loss, accuracy = model.evaluate(test_ds)\n",
        "print(\"Accuracy\", accuracy)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LmZMnTKaCZda"
      },
      "source": [
        "## 새로운 데이터로 추론하기\n",
        "\n",
        "요점: 전처리 코드가 모델 자체에 포함되어 있기 때문에 여러분이 개발한 모델은 이제 CSV 파일에서 행을 직접 분류할 수 있습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4xkOlK8Zweeh"
      },
      "source": [
        "이제 Keras 모델을 저장하고 다시 로드할 수 있습니다. TensorFlow 모델에 대한 자세한 내용은 [여기](https://www.tensorflow.org/tutorials/keras/save_and_load)에서 튜토리어를 따르세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QH9Zy1sBvwOH"
      },
      "outputs": [],
      "source": [
        "model.save('my_pet_classifier')\n",
        "reloaded_model = tf.keras.models.load_model('my_pet_classifier')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D973plJrdwQ9"
      },
      "source": [
        "새 샘플에 대한 예측값을 얻으려면, `model.predict()`를 호출하면 됩니다. 다음 두 가지만 수행해야 합니다.\n",
        "\n",
        "1. 배치 차원을 갖도록 스칼라를 목록으로 래핑합니다(모델은 단일 샘플이 아닌 데이터 배치만 처리함).\n",
        "2. 각 특성에 대해 `convert_to_tensor`를 호출합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rKq4pxtdDa7i"
      },
      "outputs": [],
      "source": [
        "sample = {\n",
        "    'Type': 'Cat',\n",
        "    'Age': 3,\n",
        "    'Breed1': 'Tabby',\n",
        "    'Gender': 'Male',\n",
        "    'Color1': 'Black',\n",
        "    'Color2': 'White',\n",
        "    'MaturitySize': 'Small',\n",
        "    'FurLength': 'Short',\n",
        "    'Vaccinated': 'No',\n",
        "    'Sterilized': 'No',\n",
        "    'Health': 'Healthy',\n",
        "    'Fee': 100,\n",
        "    'PhotoAmt': 2,\n",
        "}\n",
        "\n",
        "input_dict = {name: tf.convert_to_tensor([value]) for name, value in sample.items()}\n",
        "predictions = reloaded_model.predict(input_dict)\n",
        "prob = tf.nn.sigmoid(predictions[0])\n",
        "\n",
        "print(\n",
        "    \"This particular pet had a %.1f percent probability \"\n",
        "    \"of getting adopted.\" % (100 * prob)\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XJQQZEiH2FaB"
      },
      "source": [
        "요점: 일반적으로 더 크고 복잡한 데이터세트를 사용한 딥 러닝을 통해 최상의 결과를 얻을 수 있습니다. 작은 데이터세트로 작업할 때는 의사 결정 트리 또는 랜덤 포레스트를 강력한 기준으로 사용하는 것이 좋습니다. 이 튜토리얼의 목표는 구조적 데이터를 처리하는 메커니즘을 보여주기 위한 것이므로 향후 자체 데이터세트를 처리할 때 시작점으로 사용할 수 있는 코드를 살펴보았습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "k0QAY2Tb2HYG"
      },
      "source": [
        "## 다음 단계\n",
        "\n",
        "구조적 데이터의 분류에 대해 자세히 알아보는 가장 좋은 방법은 직접 시도해 보는 것입니다. 처리할 데이터세트를 찾고 위와 유사한 코드를 사용하여 분류하도록 모델을 훈련할 수 있습니다. 정확성을 높이려면 모델에 포함할 특성과 표현 방법을 신중하게 고려하세요."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "preprocessing_layers.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
